#ifndef ORG_WXW0303_COMMON_CXXGLIBCWRAP_H
#define ORG_WXW0303_COMMON_CXXGLIBCWRAP_H

/* glibc 的 c++ 封装;主要有以下方面的封装:
 * o 使用 C++ 异常机制来取代 errno.
 *
 * 函数声明组织.
 * o 函数声明按照 glibc 文档中定义的分类来进行分类.
 */

#include <linux/limits.h>
#include <stddef.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#include "bytearray.h"
#include "onexception.h"
#include "commonexception.h"

#if 0
/* 声明区;忽然想到,类似下面调用 open(),opendir(),DIR 都不需要头文件的.
 * 所以没有必要包括这些头文件.
 *
 * 1;忘了,某些函数声明可能带有其他修饰符.
 */
extern "C" {
/////////////13-Low Level IO Begin//////////////////////////////////////////////
int open(const char *pathname,int flags,...);
int close (int filedes);
/////////////13-Low Level IO End  //////////////////////////////////////////////

/////////////14-File System Interface Begin/////////////////////////////////////
struct __dirstream;
typedef struct __dirstream DIR;
struct dirent;

DIR* opendir(const char *name);
DIR* fdopendir(int fd);
//int dirfd(DIR *dirp);
int chdir(const char *path);
int fchdir(int fd);
int closedir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
char* getcwd (char *buffer, size_t size);
/////////////14-File System Interface End  /////////////////////////////////////
}
#endif

/////////////13-Low Level IO Begin//////////////////////////////////////////////
inline int cxx_open(const char *pathname,int flags)
{
    int fd = ::open(pathname,flags);
    if (fd == -1)
        THROW(errno,"open('%s')",pathname);
    return fd;
}

inline int cxx_open(const char *pathname,int flags,int mode)
{
    int fd = ::open(pathname,flags,mode);
    if (fd == -1)
        THROW(errno,"open('%s')",pathname);
    return fd;
}

inline void cxx_close (int filedes)
{
    // close();资源释放函数,更像析构函数;不能抛出异常.
    ::close(filedes);
}

/////////////13-Low Level IO End  //////////////////////////////////////////////

/////////////14-File System Interface Begin/////////////////////////////////////
inline DIR* cxx_opendir(const char *name)
{
    DIR *dirstream = ::opendir(name);
    if (dirstream == nullptr)
        THROW(errno,"opendir('%s')",name);
    return dirstream;
}

inline DIR* cxx_fdopendir(int fd)
{
    DIR *dirstream = ::fdopendir(fd);
    if (dirstream == nullptr)
        THROW(errno,"fdopendir");
    return dirstream;
}

inline int cxx_dirfd(DIR *dirp)
{
    int fd = ::dirfd(dirp);
    if (fd == -1)
        THROW(errno,"dirfd");
    return fd;
}

inline void cxx_chdir(const char *path)
{
    if (::chdir(path) != 0)
        THROW(errno,"chdir('%s')",path);
    return ;
}

inline void cxx_fchdir(int fd)
{
    if (::fchdir(fd) != 0)
        THROW(errno,"fchdir");
    return ;
}

inline void cxx_closedir(DIR *dirp)
{
    ::closedir(dirp);
    return ;
}

inline bool cxx_readdir_r(DIR *dirp, struct dirent *entry)
{
    struct dirent *endFlag = nullptr;
    int ret;
    if ((ret = ::readdir_r(dirp,entry,&endFlag)) != 0)
        THROW(ret,"readdir_r");
    return endFlag == nullptr ? false : true;
}

inline char* cxx_getcwd (char *buffer, size_t size)
{
    if (::getcwd(buffer,size) == nullptr)
        THROW(errno,"getcwd");
    return buffer;
}

inline void cxx_lstat(const char *pathname, struct stat *buf)
{
    if (::lstat(pathname,buf) != 0)
        THROW(errno,"lstat('%s')",pathname);
    return ;
}

// 获取文件 filename 的大小,不解析符号链接.
inline size_t getFileSize(const char *filename)
{
    struct stat filestat;
    cxx_lstat(filename,&filestat);
    return filestat.st_size;
}

inline void cxx_rename(const char *oldpath, const char *newpath)
{
    if (::rename(oldpath,newpath) != 0)
        THROW(errno,"rename('%s','%s')",oldpath,newpath);
    return ;
}

template <typename ByteArrayType>
void cxx_getcwd(ByteArrayType &bytes)
{
    size_t oldsize = bytes.size();

    bytes.resize(oldsize + PATH_MAX);
    ON_EXCEPTION {
        bytes.resize(oldsize);
    };

    char *dst = bytes.data() + oldsize;
    cxx_getcwd(dst,PATH_MAX);
    bytes.resize(oldsize + strlen(dst));
    return ;
}

inline ByteArray cxx_getcwd()
{
    ByteArray tmp;
    cxx_getcwd(tmp);
    return tmp;
}
/* 将 struct dirent.d_type 字段转化为对应的字符串描述.
 * @return 返回值指向着 .rodata 段中的某一区域.
 */
const char* direntryType2Str(int type);

inline char* cxx_mkdtemp(char *temp)
{
    char *ret = ::mkdtemp(temp);
    if (ret == nullptr)
        THROW(errno,"mkdtemp('%s')",temp);
    return ret;
}

/////////////14-File System Interface End  /////////////////////////////////////

#endif // ORG_WXW0303_COMMON_CXXGLIBCWRAP_H
